
L'une des étapes importantes dans le processus d'investissement de toute entreprise est l'identification des marchés potentiels suceptibles de générer des retours sur investissement positif. Toute entreprise avant de se lancer dans un marché se doit d'étudier ce marché afin de déceller les opportunités présentes. Dans le cadre d'un investissement dans le domaine éducatif sur le plan international, il sied de savoir:.
Telles sont les questions fondamentales que nous allons resoudre dans notre travail. Il consiste à partir des données sur l'éducation de la banque mondiale méner une analyse afin de guider une entreprise dans son programme principalement d'expansion.
La base de données est tirée du site de la banque mondiale et renseigne sur quelques indicateurs des differents pays du monde. Elle nécéssite une analyse préalable.
%matplotlib inline
import re
from os import path, getenv, environ
from typing import Dict
import folium
import matplotlib.pyplot as plt
import missingno as msno
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import pandas as pd
import plotly.express as px
import scipy
import scipy.stats as stats
import seaborn as sns
from sklearn import set_config
from sklearn.decomposition import PCA
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import MinMaxScaler
set_config(display="diagram", print_changed_only=False)
pd.set_option('display.max_columns', None)
pd.set_option('display.max_colwidth', None)
# Recupération de la localisation des fichiers pour faciliter le travail
ROOT_DIR = path.dirname(path.realpath("__file__"))
ROOT_DIR
'C:\\Users\\Administrateur\\OneDrive\\ENSAE-PARIS\\Python 2022'
# Importation de la base de données avec la fonction path.join qui prend en argument la localisation
# et le fichier des données
filepath = path.join(ROOT_DIR,"data", "bases.csv")
# ce fichier recuperé sera affecté à la varaible data et le séparateur est point virgule.
data = pd.read_csv(filepath, sep=";")
# Utilisation de shape pour afficher la taille( nombres de ligne, nombre de colonnes) de data
print("The data shape is: {shape}".format(shape=data.shape))
The data shape is: (2904, 30)
Ainsi la base comporte 2904 observations(lignes) et 30 colonnes ( variables)
# Appelation de la fonction head pour afficher les premières lignes de data
data.head()
| Country Name | Country Code | Indicator Name | Indicator Code | 2020 | Short Name | Table Name | Long Name | 2-alpha code | Currency Unit | Special Notes | Region | Income Group | WB-2 code | System of National Accounts | Alternative conversion factor | PPP survey year | Series Code | Topic | Short definition | Long definition | Unit of measure | Periodicity | Base Period | Other notes | Aggregation method | Limitations and exceptions | Notes from original source | General comments | Source | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Arab World | ARB | Expenditure on education as % of total government expenditure (%) | SE.XPD.TOTL.GB.ZS | NaN | Arab World | Arab World | Arab World | 1A | NaN | Arab World aggregate. Arab World is composed of members of the League of Arab States. | NaN | NaN | 1A | NaN | NaN | NaN | SE.XPD.TOTL.GB.ZS | Expenditures | NaN | Total general (local, regional and central) government expenditure on education (current, capital, and transfers), expressed as a percentage of total general government expenditure on all sectors (including health, education, social services, etc.). It includes expenditure funded by transfers from international sources to government. Public education expenditure includes spending by local/municipal, regional and national governments (excluding household contributions) on educational institutions (both public and private), education administration, and subsidies for private entities (students/households and other privates entities). In some instances data on total public expenditure on education refers only to the ministry of education and can exclude other ministries that spend a part of their budget on educational activities. The indicator is calculated by dividing total public expenditure on education incurred by all government agencies/departments by the total government expenditure and multiplying by 100. For more information, consult the UNESCO Institute of Statistics website: http://www.uis.unesco.org/Education/ | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | UNESCO Institute for Statistics |
| 1 | Arab World | ARB | GDP per capita, PPP (constant 2011 international $) | NY.GDP.PCAP.PP.KD | 11450.86079 | Arab World | Arab World | Arab World | 1A | NaN | Arab World aggregate. Arab World is composed of members of the League of Arab States. | NaN | NaN | 1A | NaN | NaN | NaN | NY.GDP.PCAP.PP.KD | Economic Policy & Debt: Purchasing power parity | NaN | GDP per capita based on purchasing power parity (PPP). PPP GDP is gross domestic product converted to international dollars using purchasing power parity rates. An international dollar has the same purchasing power over GDP as the U.S. dollar has in the United States. GDP at purchaser's prices is the sum of gross value added by all resident producers in the economy plus any product taxes and minus any subsidies not included in the value of the products. It is calculated without making deductions for depreciation of fabricated assets or for depletion and degradation of natural resources. Data are in constant 2011 international dollars. | NaN | Annual | 2011.0 | NaN | Weighted average | NaN | NaN | NaN | World Bank, International Comparison Program database. |
| 2 | Arab World | ARB | Government expenditure on post-secondary non-tertiary education as % of GDP (%) | UIS.XGDP.4.FSGOV | NaN | Arab World | Arab World | Arab World | 1A | NaN | Arab World aggregate. Arab World is composed of members of the League of Arab States. | NaN | NaN | 1A | NaN | NaN | NaN | UIS.XGDP.4.FSGOV | Expenditures | NaN | Total general (local, regional and central) government expenditure on post-secondary non-tertiary education (current, capital, and transfers), expressed as a percentage of GDP. It includes expenditure funded by transfers from international sources to government. Divide total government expenditure for a given level of education (ex. primary, secondary, or all levels combined) by the GDP, and multiply by 100. For more information, consult the UNESCO Institute of Statistics website: http://www.uis.unesco.org/Education/ | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | UNESCO Institute for Statistics |
| 3 | Arab World | ARB | Government expenditure on secondary education as % of GDP (%) | UIS.XGDP.23.FSGOV | NaN | Arab World | Arab World | Arab World | 1A | NaN | Arab World aggregate. Arab World is composed of members of the League of Arab States. | NaN | NaN | 1A | NaN | NaN | NaN | UIS.XGDP.23.FSGOV | Expenditures | NaN | Total general (local, regional and central) government expenditure on secondary education (current, capital, and transfers), expressed as a percentage of GDP. It includes expenditure funded by transfers from international sources to government. Divide total government expenditure for a given level of education (ex. primary, secondary, or all levels combined) by the GDP, and multiply by 100. For more information, consult the UNESCO Institute of Statistics website: http://www.uis.unesco.org/Education/ | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | UNESCO Institute for Statistics |
| 4 | Arab World | ARB | Government expenditure on tertiary education as % of GDP (%) | UIS.XGDP.56.FSGOV | NaN | Arab World | Arab World | Arab World | 1A | NaN | Arab World aggregate. Arab World is composed of members of the League of Arab States. | NaN | NaN | 1A | NaN | NaN | NaN | UIS.XGDP.56.FSGOV | Expenditures | NaN | Total general (local, regional and central) government expenditure on tertiary education (current, capital, and transfers), expressed as a percentage of GDP. It includes expenditure funded by transfers from international sources to government. Divide total government expenditure for a given level of education (ex. primary, secondary, or all levels combined) by the GDP, and multiply by 100. For more information, consult the UNESCO Institute of Statistics website: http://www.uis.unesco.org/Education/ | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | UNESCO Institute for Statistics |
Dans cette partie, il sera question d'effectuer une analyse globale de notre jeu de données. Nous allons nous interesser particulierement à:
La base de données contient plusieurs variables. Nous avons entre autres la variable indicator Name qui indique le pays correspondant, une variable qui renseigne sur les indicateurs. Ainsi pour chaque pays on donne un certain nombre d'indicateurs tels que l'utilisation de l'internet, les dépenses du gouvernement dans l'éducation,le PIB par tete. La valeur de l'indicateur est localisée dans la variable 2020. Ces données concernent l'année 2020. Par ailleurs, la base contient des données manquantes.
# Affichage des informations sur les variables( les types: float, object, character,...)
data.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 2904 entries, 0 to 2903 Data columns (total 30 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Country Name 2904 non-null object 1 Country Code 2904 non-null object 2 Indicator Name 2904 non-null object 3 Indicator Code 2904 non-null object 4 2020 1588 non-null float64 5 Short Name 2892 non-null object 6 Table Name 2892 non-null object 7 Long Name 2892 non-null object 8 2-alpha code 2856 non-null object 9 Currency Unit 2580 non-null object 10 Special Notes 1740 non-null object 11 Region 2568 non-null object 12 Income Group 2568 non-null object 13 WB-2 code 2880 non-null object 14 System of National Accounts 2580 non-null object 15 Alternative conversion factor 564 non-null object 16 PPP survey year 1740 non-null object 17 Series Code 2662 non-null object 18 Topic 2662 non-null object 19 Short definition 242 non-null object 20 Long definition 2662 non-null object 21 Unit of measure 0 non-null float64 22 Periodicity 726 non-null object 23 Base Period 242 non-null float64 24 Other notes 242 non-null object 25 Aggregation method 726 non-null object 26 Limitations and exceptions 484 non-null object 27 Notes from original source 0 non-null float64 28 General comments 484 non-null object 29 Source 2662 non-null object dtypes: float64(4), object(26) memory usage: 680.8+ KB
# Stat descriptive des variables pour avoir une vue globale des variables
data.describe(include="all")
| Country Name | Country Code | Indicator Name | Indicator Code | 2020 | Short Name | Table Name | Long Name | 2-alpha code | Currency Unit | Special Notes | Region | Income Group | WB-2 code | System of National Accounts | Alternative conversion factor | PPP survey year | Series Code | Topic | Short definition | Long definition | Unit of measure | Periodicity | Base Period | Other notes | Aggregation method | Limitations and exceptions | Notes from original source | General comments | Source | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 2904 | 2904 | 2904 | 2904 | 1.588000e+03 | 2892 | 2892 | 2892 | 2856 | 2580 | 1740 | 2568 | 2568 | 2880 | 2580 | 564 | 1740 | 2662 | 2662 | 242 | 2662 | 0.0 | 726 | 242.0 | 242 | 726 | 484 | 0.0 | 484 | 2662 |
| unique | 242 | 242 | 12 | 12 | NaN | 241 | 241 | 241 | 238 | 152 | 131 | 7 | 5 | 240 | 3 | 32 | 3 | 11 | 8 | 1 | 11 | NaN | 1 | NaN | 1 | 2 | 2 | NaN | 2 | 4 |
| top | Brunei Darussalam | TUN | Gross enrolment ratio, upper secondary, both sexes (%) | UIS.XGDP.4.FSGOV | NaN | Singapore | Brunei Darussalam | Republic of Congo | AE | Euro | April 2012 database update: Based on official government statistics, national accounts data were revised for 2000 onward; the base year changed to 2006. | Europe & Central Asia | Upper middle income | AE | Country uses the 1993 System of National Accounts methodology. | 1990–95 | 2005 | UIS.XGDP.4.FSGOV | Expenditures | The percentage of population (age 25 and over) with at least completed upper secondary education (ISCED 3 or higher). This indicator is calculated by dividing the number of persons aged 25 years and above with completed upper secondary education by the total population of the same age group and multiplying the result by 100. The UNESCO Institute for Statistics (UIS) educational attainment dataset shows the educational composition of the population aged 25 years and above and hence the stock and quality of human capital within a country. The dataset also reflects the structure and performance of the education system and its accumulated impact on human capital formation. For more information, visit the UNESCO Institute for Statistics website: http://www.uis.unesco.org/ | Total general (local, regional and central) government expenditure on education (current, capital, and transfers), expressed as a percentage of total general government expenditure on all sectors (including health, education, social services, etc.). It includes expenditure funded by transfers from international sources to government. Public education expenditure includes spending by local/municipal, regional and national governments (excluding household contributions) on educational institutions (both public and private), education administration, and subsidies for private entities (students/households and other privates entities). In some instances data on total public expenditure on education refers only to the ministry of education and can exclude other ministries that spend a part of their budget on educational activities. The indicator is calculated by dividing total public expenditure on education incurred by all government agencies/departments by the total government expenditure and multiplying by 100. For more information, consult the UNESCO Institute of Statistics website: http://www.uis.unesco.org/Education/ | NaN | Annual | NaN | Cumulative Attainment | Weighted average | Current population estimates for developing countries that lack (i) reliable recent census data, and (ii) pre- and post-census estimates for countries with census data, are provided by the United Nations Population Division and other agencies. \n\nThe cohort component method - a standard method for estimating and projecting population - requires fertility, mortality, and net migration data, often collected from sample surveys, which can be small or limited in coverage. Population estimates are from demographic modeling and so are susceptible to biases and errors from shortcomings in both the model and the data. In the UN estimates the five-year age group is the cohort unit and five-year period data are used; therefore interpolations to obtain annual data or single age structure may not reflect actual events or age composition.\n\nBecause future trends cannot be known with certainty, population projections have a wide range of uncertainty. | NaN | Please cite the International Telecommunication Union for third-party use of these data. | UNESCO Institute for Statistics |
| freq | 12 | 12 | 242 | 242 | NaN | 12 | 12 | 12 | 12 | 276 | 72 | 684 | 660 | 12 | 1980 | 96 | 1176 | 242 | 968 | 242 | 242 | NaN | 726 | NaN | 242 | 484 | 242 | NaN | 242 | 1936 |
| mean | NaN | NaN | NaN | NaN | 2.592391e+07 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 2011.0 | NaN | NaN | NaN | NaN | NaN | NaN |
| std | NaN | NaN | NaN | NaN | 2.664621e+08 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.0 | NaN | NaN | NaN | NaN | NaN | NaN |
| min | NaN | NaN | NaN | NaN | 0.000000e+00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 2011.0 | NaN | NaN | NaN | NaN | NaN | NaN |
| 25% | NaN | NaN | NaN | NaN | 6.537010e+00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 2011.0 | NaN | NaN | NaN | NaN | NaN | NaN |
| 50% | NaN | NaN | NaN | NaN | 5.044388e+01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 2011.0 | NaN | NaN | NaN | NaN | NaN | NaN |
| 75% | NaN | NaN | NaN | NaN | 2.746509e+03 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 2011.0 | NaN | NaN | NaN | NaN | NaN | NaN |
| max | NaN | NaN | NaN | NaN | 6.118075e+09 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 2011.0 | NaN | NaN | NaN | NaN | NaN | NaN |
# Fonction pour calculer les pourcentage des données manquantes par colonne (variables)
def missing_values_table(df):
# Total missing values, on pouvait utiliser isna() aussi
mis_val = df.isnull().sum()
# Pourcentage des valeurs manquantes
mis_val_percent = 100 * df.isnull().sum() / len(df)
# Tableau synthetique
mis_val_table = pd.concat([mis_val, mis_val_percent], axis=1)
# Rename the columns
mis_val_table_ren_columns = mis_val_table.rename(
columns = {0 : 'Missing Values', 1 : '% of Total Values'})
# Sort the table by percentage of missing descending
mis_val_table_ren_columns = mis_val_table_ren_columns[
mis_val_table_ren_columns.iloc[:,1] != 0].sort_values(
'% of Total Values', ascending=False).round(1)
# Print some summary information
print ("Dans la base de donnée nous avons " + str(df.shape[1]) + " columns.\n"
"il y a " + str(mis_val_table_ren_columns.shape[0]) +
" colonnes contenant des données manquantes.")
# Return the dataframe with missing information
return mis_val_table_ren_columns
# Fonction resume statistique
def resumetable(df):
print(f"Dataset Shape: {df.shape}")
summary = pd.DataFrame(df.dtypes,columns=['dtypes'])
summary = summary.reset_index()
summary['Name'] = summary['index']
summary = summary[['Name','dtypes']]
summary['Missing'] = df.isnull().sum().values
summary['Uniques'] = df.nunique().values
summary['First Value'] = df.iloc[0].values
summary['Second Value'] = df.iloc[1].values
summary['Third Value'] = df.iloc[2].values
for name in summary['Name'].value_counts().index:
summary.loc[summary['Name'] == name, 'Entropy'] = round(stats.entropy(df[name].value_counts(normalize=True), base=2),2)
return summary
def cross_heatmap(df, cols, normalize=False, values=None, aggfunc=None):
temp = cols
cm = sns.light_palette("green", as_cmap=True)
return pd.crosstab(df[temp[0]], df[temp[1]],
normalize=normalize, values=values, aggfunc=aggfunc).style.background_gradient(cmap = cm)
missing_values_table(data)
Dans la base de donnée nous avons 30 columns. il y a 26 colonnes contenant des données manquantes.
| Missing Values | % of Total Values | |
|---|---|---|
| Notes from original source | 2904 | 100.0 |
| Unit of measure | 2904 | 100.0 |
| Short definition | 2662 | 91.7 |
| Base Period | 2662 | 91.7 |
| Other notes | 2662 | 91.7 |
| General comments | 2420 | 83.3 |
| Limitations and exceptions | 2420 | 83.3 |
| Alternative conversion factor | 2340 | 80.6 |
| Periodicity | 2178 | 75.0 |
| Aggregation method | 2178 | 75.0 |
| 2020 | 1316 | 45.3 |
| PPP survey year | 1164 | 40.1 |
| Special Notes | 1164 | 40.1 |
| Region | 336 | 11.6 |
| Income Group | 336 | 11.6 |
| System of National Accounts | 324 | 11.2 |
| Currency Unit | 324 | 11.2 |
| Series Code | 242 | 8.3 |
| Long definition | 242 | 8.3 |
| Topic | 242 | 8.3 |
| Source | 242 | 8.3 |
| 2-alpha code | 48 | 1.7 |
| WB-2 code | 24 | 0.8 |
| Short Name | 12 | 0.4 |
| Long Name | 12 | 0.4 |
| Table Name | 12 | 0.4 |
Bien que certaines variables ne nous interesseront pas ou n'ont pas d'informations pertinentes, il faut tout de meme noter la presence de beaucoups de missing values.
Par ailleurs les noms des variabales contiennent des caracteres pas tres comode dans l'usage, il serait necessaire de les renommer pour faciliter la manipulation.
## Recherche de doublons
data.duplicated().sum()
0
# Renommer les variables contenant des espaces avec la fonction replace ( espace devient tiret de huit)
# Rename columns: replace space & - by _
data.columns = data.columns.str.lower().str.replace('[-\s]', '_', regex=True)
data.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 2904 entries, 0 to 2903 Data columns (total 30 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 country_name 2904 non-null object 1 country_code 2904 non-null object 2 indicator_name 2904 non-null object 3 indicator_code 2904 non-null object 4 2020 1588 non-null float64 5 short_name 2892 non-null object 6 table_name 2892 non-null object 7 long_name 2892 non-null object 8 2_alpha_code 2856 non-null object 9 currency_unit 2580 non-null object 10 special_notes 1740 non-null object 11 region 2568 non-null object 12 income_group 2568 non-null object 13 wb_2_code 2880 non-null object 14 system_of_national_accounts 2580 non-null object 15 alternative_conversion_factor 564 non-null object 16 ppp_survey_year 1740 non-null object 17 series_code 2662 non-null object 18 topic 2662 non-null object 19 short_definition 242 non-null object 20 long_definition 2662 non-null object 21 unit_of_measure 0 non-null float64 22 periodicity 726 non-null object 23 base_period 242 non-null float64 24 other_notes 242 non-null object 25 aggregation_method 726 non-null object 26 limitations_and_exceptions 484 non-null object 27 notes_from_original_source 0 non-null float64 28 general_comments 484 non-null object 29 source 2662 non-null object dtypes: float64(4), object(26) memory usage: 680.8+ KB
# Vue globale sur les régions représentées à l'aide d'un diagramme circulaire( chaque région avec son nombre de pays: en pourcentage)
(data.region
.value_counts(dropna=False)
.plot(kind="pie", autopct='%.1f%%', legend = False, fontsize=10,
xlabel="", ylabel="", table=False, figsize=(5, 5))
);
Toutes les zones sont représentées. Mais il existe une région nan qui contient 11,6% de pays. Ce sont des erreurs d'observations cela veut dire que ces pays n'ont pas de régions ce qui est contradictoire. Nous allons ainsi supprimer ces pays sans region.
# Affichage des pays correspondant à des régions manquantes à l'aide de la fonction loc. Cette fonction nous affiche les pays sans région
data.loc[data.region.isnull(), "country_name"].unique()
array(['Arab World', 'East Asia & Pacific',
'East Asia & Pacific (excluding high income)', 'Euro area',
'Europe & Central Asia',
'Europe & Central Asia (excluding high income)', 'European Union',
'Heavily indebted poor countries (HIPC)', 'High income',
'Latin America & Caribbean',
'Latin America & Caribbean (excluding high income)',
'Least developed countries: UN classification',
'Low & middle income', 'Low income', 'Lower middle income',
'Middle East & North Africa',
'Middle East & North Africa (excluding high income)',
'Middle income', 'North America', 'OECD members', 'South Asia',
'Sub-Saharan Africa', 'Sub-Saharan Africa (excluding high income)',
'Upper middle income', 'World', 'British Virgin Islands',
'Gibraltar', 'Nauru'], dtype=object)
L'on constate que certains sont des zone et d'autre des pays.
# Suppression de tous les pays sans region( avec région manquante)
data = data.loc[data.region.notnull()]
missing_values_table(data)
Dans la base de donnée nous avons 30 columns. il y a 19 colonnes contenant des données manquantes.
| Missing Values | % of Total Values | |
|---|---|---|
| notes_from_original_source | 2568 | 100.0 |
| unit_of_measure | 2568 | 100.0 |
| other_notes | 2354 | 91.7 |
| short_definition | 2354 | 91.7 |
| base_period | 2354 | 91.7 |
| general_comments | 2140 | 83.3 |
| limitations_and_exceptions | 2140 | 83.3 |
| alternative_conversion_factor | 2004 | 78.0 |
| aggregation_method | 1926 | 75.0 |
| periodicity | 1926 | 75.0 |
| 2020 | 1132 | 44.1 |
| special_notes | 1128 | 43.9 |
| ppp_survey_year | 828 | 32.2 |
| long_definition | 214 | 8.3 |
| topic | 214 | 8.3 |
| series_code | 214 | 8.3 |
| source | 214 | 8.3 |
| 2_alpha_code | 36 | 1.4 |
| wb_2_code | 12 | 0.5 |
# retouver les colonnes qui dépassent 90 %
missing_df = missing_values_table(data);
missing_columns= list(missing_df[missing_df['% of Total Values'] > 90].index)
print('Nous allons supprimer les %d colonnes contenant plus de 90 pour cent de valeurs manquantes.' % len(missing_columns))
Dans la base de donnée nous avons 30 columns. il y a 19 colonnes contenant des données manquantes. Nous allons supprimer les 5 colonnes contenant plus de 90 pour cent de valeurs manquantes.
Missingno est une bibliothèque Python qui permet de comprendre la distribution des valeurs manquantes grâce à des visualisations informatives. Ces visualisations peuvent prendre la forme de heat_map ou de diagrammes à bar. Avec cette bibliothèque, il est possible d'observer où les valeurs manquantes sont apparues et de vérifier la corrélation des colonnes contenant les valeurs manquantes avec la colonne cible. Les valeurs manquantes sont mieux traitées une fois que l'ensemble de données est entièrement exploré. Mettons maintenant cette bibliothèque en œuvre et découvrons comment elle nous aide à mieux prétraiter les données.
# Observation de la distribution des valeurs manquantes par colonne (histogramme)
msno.bar(data, figsize=(20, 7), fontsize=10);
Les variables ayant un bar court ont beaucoups de missings values. Mais la plupart d'entre elle concerne des metadonnées.
#Distribution des valeurs manquantes par la fonction matrix: elle nous indique les positions des valeurs manquantes
msno.matrix(data, figsize=(25, 10), fontsize=10);
Le heat map permet d'observer les positions des valeurs manquantes. Ainsi certaines variables prennent simultanement des missings values.
### Fréquence de la variable income group (histogramme par groupe de revenu)
data.income_group.value_counts().plot(kind="barh");
La modalite Upper middle income est la plus frequente, autrement il ya plus de pays avec un revenu moyen legerement eleve. Nous recherchons les pays ou le revenu est assez eleve susceptible de nous procurer un retour sur investissement positif. Pour cela les pays avec revenu faible peuvent etre ecartes.
Il s'agit des pays tels que Afghanistan,Armenia, Bangladesh entre autres.
# filtrer low income group: Ce sont des pays à RNB(Revenu national Brut) par habitant inferieur ou égal à 1000 dollars selon la
# banque mondiale
# Nous allons recupérer ces pays et les écarter de l'analyse car ils n'ont pas de fort potentiel éducatif
LOW_INCOME_FILTER = data.income_group.str.contains("low", regex=True, flags=re.I, na=False)
data.loc[LOW_INCOME_FILTER, "country_name"].unique()
array(['Afghanistan', 'Armenia', 'Bangladesh', 'Benin', 'Bhutan',
'Bolivia', 'Burkina Faso', 'Burundi', 'Cabo Verde', 'Cambodia',
'Cameroon', 'Central African Republic', 'Chad', 'Comoros',
'Congo, Dem. Rep.', 'Congo, Rep.', "Cote d'Ivoire", 'Djibouti',
'Egypt, Arab Rep.', 'El Salvador', 'Eritrea', 'Ethiopia',
'Gambia, The', 'Georgia', 'Ghana', 'Guatemala', 'Guinea',
'Guinea-Bissau', 'Guyana', 'Haiti', 'Honduras', 'India',
'Indonesia', 'Kenya', 'Kiribati', 'Korea, Dem. People’s Rep.',
'Kosovo', 'Kyrgyz Republic', 'Lao PDR', 'Lesotho', 'Liberia',
'Madagascar', 'Malawi', 'Mali', 'Mauritania',
'Micronesia, Fed. Sts.', 'Moldova', 'Mongolia', 'Morocco',
'Mozambique', 'Myanmar', 'Nepal', 'Nicaragua', 'Niger', 'Nigeria',
'Pakistan', 'Papua New Guinea', 'Paraguay', 'Philippines',
'Rwanda', 'Samoa', 'Sao Tome and Principe', 'Senegal',
'Sierra Leone', 'Solomon Islands', 'Somalia', 'South Sudan',
'Sri Lanka', 'Sudan', 'Swaziland', 'Syrian Arab Republic',
'Tajikistan', 'Tanzania', 'Timor-Leste', 'Togo', 'Uganda',
'Ukraine', 'Uzbekistan', 'Vanuatu', 'Vietnam',
'West Bank and Gaza', 'Yemen, Rep.', 'Zambia', 'Zimbabwe'],
dtype=object)
# Ne garder que les pays n'ayant pas de faible RNB par habitant
data = data.loc[~LOW_INCOME_FILTER]
print(f"data shape: {data.shape}")
data shape: (1560, 30)
missing_values_table(data)
Dans la base de donnée nous avons 30 columns. il y a 19 colonnes contenant des données manquantes.
| Missing Values | % of Total Values | |
|---|---|---|
| notes_from_original_source | 1560 | 100.0 |
| unit_of_measure | 1560 | 100.0 |
| other_notes | 1430 | 91.7 |
| short_definition | 1430 | 91.7 |
| base_period | 1430 | 91.7 |
| alternative_conversion_factor | 1320 | 84.6 |
| general_comments | 1300 | 83.3 |
| limitations_and_exceptions | 1300 | 83.3 |
| aggregation_method | 1170 | 75.0 |
| periodicity | 1170 | 75.0 |
| special_notes | 720 | 46.2 |
| 2020 | 675 | 43.3 |
| ppp_survey_year | 564 | 36.2 |
| long_definition | 130 | 8.3 |
| topic | 130 | 8.3 |
| series_code | 130 | 8.3 |
| source | 130 | 8.3 |
| 2_alpha_code | 24 | 1.5 |
| wb_2_code | 12 | 0.8 |
Interressons nous maintenant aux indicateurs disponible dans la base.
#Ce sont les indicateurs qui nous serviront dans la suite, pour notre analyse
#Affichage de la liste des indicateurs( noms et code par ordre croissant de code)
(data
.loc[:, ["indicator_name", "indicator_code"]] # les noms et code des indicateurs
.drop_duplicates()
.sort_values(by="indicator_code")
.reset_index(drop=True)
)
| indicator_name | indicator_code | |
|---|---|---|
| 0 | Internet users (per 100 people) | IT.NET.USER.P2 |
| 1 | GDP per capita, PPP (constant 2011 international $) | NY.GDP.PCAP.PP.KD |
| 2 | Gross enrolment ratio, upper secondary, both sexes (%) | SE.SEC.ENRR.UP |
| 3 | Gross enrolment ratio, tertiary, both sexes (%) | SE.TER.ENRR |
| 4 | Expenditure on education as % of total government expenditure (%) | SE.XPD.TOTL.GB.ZS |
| 5 | Population, ages 15-64 (% of total) | SP.POP.1564.TO.ZS |
| 6 | Population, total | SP.POP.TOTL |
| 7 | UIS: Percentage of population age 25+ with at least completed upper secondary education (ISCED 3 or higher). Total | UIS.EA.3T6.AG25T99 |
| 8 | Gross enrolment ratio, post-secondary non-tertiary, both sexes (%) | UIS.GER.4 |
| 9 | Government expenditure on secondary education as % of GDP (%) | UIS.XGDP.23.FSGOV |
| 10 | Government expenditure on post-secondary non-tertiary education as % of GDP (%) | UIS.XGDP.4.FSGOV |
| 11 | Government expenditure on tertiary education as % of GDP (%) | UIS.XGDP.56.FSGOV |
Nous avons entre autre l'utilisation d'internet, le pib par habitant (PPP 2011), la ratio d'enrollement, les depenses du gouvernement, etc.
Nous allons decrire le nombre d'indicateurs par pays.
# description du nombre d'indicateurs par pays
df_nb_indicators_by_country = data.groupby(["region", "country_name", "country_code"],
as_index=False, dropna=False)["2020"].count()
df_nb_indicators_by_country.head()
| region | country_name | country_code | 2020 | |
|---|---|---|---|---|
| 0 | East Asia & Pacific | American Samoa | ASM | 1 |
| 1 | East Asia & Pacific | Australia | AUS | 11 |
| 2 | East Asia & Pacific | Brunei Darussalam | BRN | 8 |
| 3 | East Asia & Pacific | China | CHN | 7 |
| 4 | East Asia & Pacific | Fiji | FJI | 8 |
Par exemple Il ya des pays qui n'ont qu'un seul indicateur. Il ne sera pas interressant de faire l'analyse sur un seul indicateur.
Il semble que la plupart des pays ont entre 6 et 8 indicateurs.
df_nb_indicators_by_country.plot(kind="hist", title="Distribution - nombre d'indicateur par pays");
En utilisant les code des pays nous pouvons representer le maps des pays selon le nombre d'indicateurs. Ainsi en jaune les pays (la France par exemple) qui ont nombre d'indicateurs eleves et en bleu ceux ayant un nombre faible d'indicateurs.
# La carte des pays selon le nombre d'indicateurs disponible
px.choropleth(df_nb_indicators_by_country,
locations="country_code", # Cette valeur est interprétée en fonction du mode de localisation et convertie en longitude/latitude
color="2020",
# hover_name="country_name",
hover_data=["region", "country_name", "country_code"],
animation_frame=None,
height=500,
width=None,
title="Nombre d'indicateur par pays",
#range_color=(0, 12),
)
# On va utiliser le quantile d'ordre 1(25%) du nombre d'indicateur disponoble pour filtrer les pays
quantile1 = df_nb_indicators_by_country.quantile(.25).values[0]
# countries that have less than 5 indicators, ces pays ne contiennent pas suffisament d'indicateurs pour l'analyse
moins_quantile1_indicateurs = df_nb_indicators_by_country.loc[df_nb_indicators_by_country["2020"] <= quantile1,
"country_name"]
display(moins_quantile1_indicateurs)
data = data.loc[~data.country_name.isin(moins_quantile1_indicateurs)]
0 American Samoa 5 French Polynesia 6 Guam 7 Hong Kong SAR, China 12 Marshall Islands 13 New Caledonia 15 Northern Mariana Islands 16 Palau 17 Singapore 20 Tuvalu 22 Andorra 25 Belarus 27 Bosnia and Herzegovina 29 Channel Islands 35 Faroe Islands 40 Greenland 44 Isle of Man 48 Liechtenstein 52 Monaco 53 Montenegro 60 San Marino 61 Serbia 68 Turkmenistan 77 Cayman Islands 82 Curacao 83 Dominica 86 Grenada 91 Puerto Rico 92 Sint Maarten (Dutch part) 95 St. Martin (French part) 97 Suriname 99 Turks and Caicos Islands 102 Virgin Islands (U.S.) 111 Libya 117 United Arab Emirates 118 Bermuda 121 Maldives 125 Gabon Name: country_name, dtype: object
sns.catplot(data=data, y='region', x='2020', col='indicator_code',
height=5, aspect=1.5, palette="husl", orient="h",
col_wrap=2, kind="box", sharex=False, sharey=True);
# topn (n=10) of country by indicator: On a ainsi le top des 10 pays par indicateur
N = 10
df_country_by_indicator = (data
.groupby(['indicator_name'], as_index=True, dropna=False)
[['region', 'country_name', '2020']]
.apply(lambda x: x.nlargest(N, columns=['2020'], keep="all"))
.reset_index()
)
df_country_by_indicator
| indicator_name | level_1 | region | country_name | 2020 | |
|---|---|---|---|---|---|
| 0 | Expenditure on education as % of total government expenditure (%) | 2496 | Latin America & Caribbean | St. Vincent and the Grenadines | 30.789200 |
| 1 | Expenditure on education as % of total government expenditure (%) | 2604 | East Asia & Pacific | Thailand | 28.388599 |
| 2 | Expenditure on education as % of total government expenditure (%) | 2664 | Middle East & North Africa | Tunisia | 25.047310 |
| 3 | Expenditure on education as % of total government expenditure (%) | 2640 | East Asia & Pacific | Tonga | 22.955860 |
| 4 | Expenditure on education as % of total government expenditure (%) | 1932 | Sub-Saharan Africa | Namibia | 21.925060 |
| ... | ... | ... | ... | ... | ... |
| 115 | UIS: Percentage of population age 25+ with at least completed upper secondary education (ISCED 3 or higher). Total | 2291 | Middle East & North Africa | Saudi Arabia | 30.066601 |
| 116 | UIS: Percentage of population age 25+ with at least completed upper secondary education (ISCED 3 or higher). Total | 503 | Latin America & Caribbean | Barbados | 24.205730 |
| 117 | UIS: Percentage of population age 25+ with at least completed upper secondary education (ISCED 3 or higher). Total | 1787 | Middle East & North Africa | Malta | 20.398439 |
| 118 | UIS: Percentage of population age 25+ with at least completed upper secondary education (ISCED 3 or higher). Total | 1823 | Sub-Saharan Africa | Mauritius | 20.398439 |
| 119 | UIS: Percentage of population age 25+ with at least completed upper secondary education (ISCED 3 or higher). Total | 1835 | Latin America & Caribbean | Mexico | 18.577311 |
120 rows × 5 columns
#Plot des pays dans le top10 Les couleurs indiquent les regions auxquelles appartiennent les pays et le bar la valeurs detenues par le pays
g = sns.catplot(data=df_country_by_indicator,
y="country_name",
x="2020",
kind="bar",
orient="h",
height=5,
aspect=1.7,
hue="region",
col="indicator_name",
col_wrap=2,
sharey=False,
sharex=False,
)
g.set_axis_labels("", "")
<seaborn.axisgrid.FacetGrid at 0x1c030297280>
La disposition des variables ne permet pas d'implementer certaines methodes statistique car ce sont les indicateurs qui constituent nos variables danalyse. Il faut donc que les indicateurs soient en colonne et les pays en ligne. Ainsi la commande pivot de la balise pandas sera utilisée. Elle fonctionne exactement comme la commande reshape sur stata. Ainsi nous obtenons une base qui nous renseigne pour chaque pays ou zone les différents indicateurs. La commande pivot nous a facilité ici la tache au lieu de procéder à des manipulation longues. Implicitement, nous allons éliminer plusieurs colonnes qui ne contenaient jusque là que des métadonnées(des informations sur les calcul des indicateurs).
# Create a spreadsheet-style pivot table as a DataFrame.
data_pivot = pd.pivot_table(data=data,
index=["region", "country_name", "country_code"],
values='2020',
columns='indicator_code').reset_index()
print(f"Data shape: {data_pivot.shape}")
data_pivot.head()
Data shape: (92, 15)
| indicator_code | region | country_name | country_code | IT.NET.USER.P2 | NY.GDP.PCAP.PP.KD | SE.SEC.ENRR.UP | SE.TER.ENRR | SE.XPD.TOTL.GB.ZS | SP.POP.1564.TO.ZS | SP.POP.TOTL | UIS.EA.3T6.AG25T99 | UIS.GER.4 | UIS.XGDP.23.FSGOV | UIS.XGDP.4.FSGOV | UIS.XGDP.56.FSGOV |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | East Asia & Pacific | Australia | AUS | 46.756116 | 35281.395362 | 249.607498 | 67.03891 | 13.360160 | 66.788576 | 1.915300e+07 | NaN | 61.390049 | 1.88884 | 0.07649 | 1.14633 |
| 1 | East Asia & Pacific | Brunei Darussalam | BRN | 8.996285 | 82049.580860 | 67.462151 | 12.69113 | 8.920740 | 66.955147 | 3.332410e+05 | NaN | 1.296230 | NaN | NaN | NaN |
| 2 | East Asia & Pacific | China | CHN | 1.775913 | 3700.743648 | 38.959030 | 7.72048 | NaN | 68.462574 | 1.262645e+09 | NaN | 5.307240 | NaN | NaN | NaN |
| 3 | East Asia & Pacific | Fiji | FJI | 1.496855 | 6673.847391 | 59.116379 | NaN | 20.484921 | 61.538812 | 8.112230e+05 | NaN | 2.885000 | NaN | NaN | 0.84457 |
| 4 | East Asia & Pacific | Japan | JPN | 29.990740 | 33871.843545 | 100.454224 | 48.73653 | 9.930410 | 68.232188 | 1.268430e+08 | NaN | 0.844730 | 1.44606 | NaN | 0.54858 |
# Description de la nouvelle base
data_pivot.describe(include="all")
| indicator_code | region | country_name | country_code | IT.NET.USER.P2 | NY.GDP.PCAP.PP.KD | SE.SEC.ENRR.UP | SE.TER.ENRR | SE.XPD.TOTL.GB.ZS | SP.POP.1564.TO.ZS | SP.POP.TOTL | UIS.EA.3T6.AG25T99 | UIS.GER.4 | UIS.XGDP.23.FSGOV | UIS.XGDP.4.FSGOV | UIS.XGDP.56.FSGOV |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 92 | 92 | 92 | 91.000000 | 90.000000 | 84.000000 | 69.000000 | 63.000000 | 91.000000 | 9.200000e+01 | 11.000000 | 56.000000 | 46.000000 | 25.000000 | 47.000000 |
| unique | 6 | 92 | 92 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| top | Europe & Central Asia | United States | SVK | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| freq | 36 | 1 | 1 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| mean | NaN | NaN | NaN | 13.456444 | 23297.936342 | 81.920940 | 38.041727 | 14.193053 | 64.749554 | 3.592016e+07 | 36.865614 | 16.628987 | 1.814862 | 0.087523 | 0.983590 |
| std | NaN | NaN | NaN | 14.729495 | 18997.157329 | 35.704867 | 19.611261 | 5.344908 | 4.236421 | 1.359502e+08 | 21.497669 | 14.870619 | 0.587587 | 0.108619 | 0.455717 |
| min | NaN | NaN | NaN | 0.105046 | 3508.905125 | 8.165120 | 3.234750 | 4.964300 | 50.130735 | 4.537400e+04 | 15.675070 | 0.335280 | 0.397710 | 0.001670 | 0.059390 |
| 25% | NaN | NaN | NaN | 3.180408 | 10260.927062 | 59.539659 | 22.362659 | 10.375395 | 62.227768 | 1.645501e+06 | 20.398439 | 5.921795 | 1.420477 | 0.023290 | 0.741090 |
| 50% | NaN | NaN | NaN | 6.731396 | 15654.111790 | 80.134777 | 37.147419 | 13.360160 | 65.567704 | 6.736625e+06 | 30.066601 | 12.091540 | 1.831825 | 0.047550 | 0.869290 |
| 75% | NaN | NaN | NaN | 17.225234 | 34689.708142 | 98.578098 | 54.428761 | 16.599045 | 67.859249 | 2.379614e+07 | 50.060844 | 26.575469 | 2.111583 | 0.127030 | 1.214570 |
| max | NaN | NaN | NaN | 52.000000 | 108323.903919 | 249.607498 | 82.439072 | 30.789200 | 72.588714 | 1.262645e+09 | 71.459663 | 61.390049 | 2.970210 | 0.536130 | 2.425410 |
missing_values_table(data_pivot)
Dans la base de donnée nous avons 15 columns. il y a 11 colonnes contenant des données manquantes.
| Missing Values | % of Total Values | |
|---|---|---|
| indicator_code | ||
| UIS.EA.3T6.AG25T99 | 81 | 88.0 |
| UIS.XGDP.4.FSGOV | 67 | 72.8 |
| UIS.XGDP.23.FSGOV | 46 | 50.0 |
| UIS.XGDP.56.FSGOV | 45 | 48.9 |
| UIS.GER.4 | 36 | 39.1 |
| SE.XPD.TOTL.GB.ZS | 29 | 31.5 |
| SE.TER.ENRR | 23 | 25.0 |
| SE.SEC.ENRR.UP | 8 | 8.7 |
| NY.GDP.PCAP.PP.KD | 2 | 2.2 |
| IT.NET.USER.P2 | 1 | 1.1 |
| SP.POP.1564.TO.ZS | 1 | 1.1 |
#Visualisons à nouveau les valeurs manquantes de la base
msno.bar(data_pivot);
msno.matrix(data_pivot);
Nous avons des variables renseignant sur les depenses du gouvernement, sur les taux de scolarisation. Nous allons en creer une seule variable aggregant toutes ces vriables.
#liste des variables(indicteurs) de data_pivot
indicators = ['IT.NET.USER.P2', # internet
"NY.GDP.PCAP.PP.KD", # GDP
"SP.POP.1564.TO.ZS", # population
# enrolment
"SE.SEC.ENRR.UP",
"SE.TER.ENRR",
"UIS.GER.4",
# expenditure
"SE.XPD.TOTL.GB.ZS",
"UIS.XGDP.23.FSGOV",
"UIS.XGDP.4.FSGOV",
"UIS.XGDP.56.FSGOV",
]
len(indicators)
10
# Création de nouvelles variables
# total_enrolment= moyenne des trois taux de scolarisation( secondaire,post-secondaire non-supérieur, supérieur)
# gov_expenditure= somme des dépenses du gouvernement( secondaire,post-secondaire non-supérieur, supérieur)
# Renommer les variables(indicateurs) SE.XPD.TOTL.GB.ZS ; IT.NET.USER.P2 ; NY.GDP.PCAP.PP.KD .
data_pivot = (data_pivot
.assign(total_enrolment=lambda dframe: dframe[["SE.SEC.ENRR.UP", "SE.TER.ENRR", "UIS.GER.4"]
].mean(axis=1),
gov_expenditure=lambda dframe: (dframe["UIS.XGDP.23.FSGOV"]
+ dframe["UIS.XGDP.4.FSGOV"]
+ dframe["UIS.XGDP.56.FSGOV"]
),
)
.rename(columns={"SE.XPD.TOTL.GB.ZS": "percent_education_total_gov_expenditure",
"IT.NET.USER.P2": "internet_users",
"NY.GDP.PCAP.PP.KD": "gdp_per_capita"})
)
data_pivot.head()
| indicator_code | region | country_name | country_code | internet_users | gdp_per_capita | SE.SEC.ENRR.UP | SE.TER.ENRR | percent_education_total_gov_expenditure | SP.POP.1564.TO.ZS | SP.POP.TOTL | UIS.EA.3T6.AG25T99 | UIS.GER.4 | UIS.XGDP.23.FSGOV | UIS.XGDP.4.FSGOV | UIS.XGDP.56.FSGOV | total_enrolment | gov_expenditure |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | East Asia & Pacific | Australia | AUS | 46.756116 | 35281.395362 | 249.607498 | 67.03891 | 13.360160 | 66.788576 | 1.915300e+07 | NaN | 61.390049 | 1.88884 | 0.07649 | 1.14633 | 126.012152 | 3.11166 |
| 1 | East Asia & Pacific | Brunei Darussalam | BRN | 8.996285 | 82049.580860 | 67.462151 | 12.69113 | 8.920740 | 66.955147 | 3.332410e+05 | NaN | 1.296230 | NaN | NaN | NaN | 27.149837 | NaN |
| 2 | East Asia & Pacific | China | CHN | 1.775913 | 3700.743648 | 38.959030 | 7.72048 | NaN | 68.462574 | 1.262645e+09 | NaN | 5.307240 | NaN | NaN | NaN | 17.328917 | NaN |
| 3 | East Asia & Pacific | Fiji | FJI | 1.496855 | 6673.847391 | 59.116379 | NaN | 20.484921 | 61.538812 | 8.112230e+05 | NaN | 2.885000 | NaN | NaN | 0.84457 | 31.000689 | NaN |
| 4 | East Asia & Pacific | Japan | JPN | 29.990740 | 33871.843545 | 100.454224 | 48.73653 | 9.930410 | 68.232188 | 1.268430e+08 | NaN | 0.844730 | 1.44606 | NaN | 0.54858 | 50.011828 | NaN |
# Grille des Histogrammes
data_pivot.hist(figsize=(14,14))
plt.show()
plt.figure(figsize=(15,7))
sns.heatmap(data_pivot.corr(),annot=True,vmin=-1,vmax=1,fmt='.2f',cmap='Spectral')
plt.show()
Dans cette partie, nous allons construire un score d'attractivité. Celui-ci nous permettra d'ordonner les pays en fonction de leur attractivité en terme d'investissement dans l'éducation.
Pour ce faire nous allons utiliser deux méthodes, la première est une pondération et la deuxième est une analyse en composante principale.
Nous utiliserons par la suite les variables internet, pib par habitant, l'enrollement total et les depenses du gouvernement.
# Ici on s'intéresse aux variables clés : le nombre d'utilisateurs d'internet, le PIB par habitant,
# le taux moyen de scolarisation et les dépenses totales du gouvernement dans l'éducation(en %).
# La liste des indicateurs pour le score d'attractivité
list_features = ["internet_users",
"gdp_per_capita",
"total_enrolment",
"percent_education_total_gov_expenditure",
]
# Définition de la fonction Scoring
def scoring(dframe: pd.DataFrame, ## the data frame
features_weight: Dict[str, float] # Dictionnaire des noms des variables et leur importance
) -> float:
""" Country attractivity score
Args:
dframe (pd.DataFrame): data frame
Returns:
float: attractivity score
"""
score = 0
for col_name, weight in features_weight.items():
score += weight * dframe[col_name] ## Somme ponderee de leur importance
return score
# internet users stats np.arange(0, 1, 0.1) to creat a range of decile frequences values 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9
internet_stat = data_pivot["internet_users"].describe(percentiles=np.arange(0, 1, 0.1))
internet_stat
count 91.000000 mean 13.456444 std 14.729495 min 0.105046 0% 0.105046 10% 1.496855 20% 2.750740 30% 3.689041 40% 5.800253 50% 6.731396 60% 8.996285 70% 15.110260 80% 23.110874 90% 43.079163 max 52.000000 Name: internet_users, dtype: float64
# filter out all coutries that have internet_users less thant 60% decile
data_f = data_pivot.loc[data_pivot["internet_users"] >= internet_stat.loc["60%"], :].copy()
data_f.country_name.unique()
array(['Australia', 'Japan', 'Korea, Rep.', 'Macao SAR, China',
'Malaysia', 'New Zealand', 'Austria', 'Belgium', 'Cyprus',
'Czech Republic', 'Denmark', 'Estonia', 'Finland', 'France',
'Germany', 'Greece', 'Iceland', 'Ireland', 'Italy', 'Luxembourg',
'Netherlands', 'Norway', 'Portugal', 'Slovak Republic', 'Slovenia',
'Spain', 'Sweden', 'Switzerland', 'United Kingdom', 'Aruba',
'Chile', 'Uruguay', 'Israel', 'Malta', 'Canada', 'United States'],
dtype=object)
print(f'Nous avons desormais une base de shape: {data_f.shape}')
Nous avons desormais une base de shape: (36, 17)
Nous avons affecté des coefficients ou poids aux variables sur la base de la litterature ou selon l'importance de la variable.
# Il s'agit d'affecter des coefficients( poids) à chaque variable en fonction de son importance que nous considerons.
# custom weighted
f_w = {"internet_users": .3,
"total_enrolment": .3,
"gdp_per_capita": .3,
"percent_education_total_gov_expenditure": .1,
}
data_f = (data_f
.assign(attractivity_score_custom=
lambda dframe: dframe.apply(scoring, features_weight=f_w, axis=1))
.reset_index()
)
# et on obtient
data_f[list_features + ["attractivity_score_custom"]].head()
| indicator_code | internet_users | gdp_per_capita | total_enrolment | percent_education_total_gov_expenditure | attractivity_score_custom |
|---|---|---|---|---|---|
| 0 | 46.756116 | 35281.395362 | 126.012152 | 13.36016 | 10637.585105 |
| 1 | 29.990740 | 33871.843545 | 50.011828 | 9.93041 | 10186.546875 |
| 2 | 44.700000 | 20756.779897 | 87.160423 | NaN | NaN |
| 3 | 13.608590 | 42225.415419 | 42.917110 | NaN | NaN |
| 4 | 21.384731 | 16309.967988 | 30.441227 | 21.39068 | 4910.677252 |
dix_countries = data_f.nlargest(N, columns=["attractivity_score_custom"], keep="all")
g = sns.catplot(data=dix_countries,
kind="bar", orient="h", hue=None,
y="country_name", x="attractivity_score_custom", estimator=np.mean,
height=5, aspect=1.4, palette="Blues_r",
)
g.ax.set_title("les pays selectionnés");
Ainsi selon les poids affectés suivant cette méthode de pondération on peut retenir les pays suivants: Norway, Switzerland, le Denmark, Ntherlands, Australia, l'ireland, le canada, Suisse, l'italie. Et le Norway apparait comme le premier pays en terme de qualité et d'attractivité dans le domaine éducatif.
Dans cette partie nous allons mener une méthode d'analyse en composante principale.
# Visualisation des pays dans le plan des variables (3 indicateurs):
# Difficile d'interprétation et de décision d'ou l'intéret de l'ACP
fig = px.scatter_3d(data_frame=data_pivot,
x="internet_users",
y="gdp_per_capita",
z='total_enrolment',
color='region',
hover_name="country_name",
symbol='region',
opacity=0.7,
width=800,
height=500,
)
# tight layout
fig.update_layout(margin=dict(l=0, r=0, b=0, t=0))
# Définition de la fonction fillna( elle permettra d'imputer les valeurs manquantes par la médiane)
#
def fillna_by_group(data, groupby, columns, estimator="median"):
# union permet de combiner plusieurs types
""" Fill na by group
Args:
data (pd.DataFrame):
groupby (Union[str, Sequence[str]]):
columns (Union[str, Sequence[str]]):
estimator (str):
Return:
pd.DataFrame
"""
return data_pivot[columns].fillna(data_pivot.groupby(groupby)[columns].transform(estimator))
# Imputer les valeurs manquantes: Nous remplaçons les valeurs manquantes par la moyenne des observations
data_pivot[list_features] = fillna_by_group(data=data_pivot,
groupby="region",
columns=list_features,
estimator="median",
)
data_pivot.head()
| indicator_code | region | country_name | country_code | internet_users | gdp_per_capita | SE.SEC.ENRR.UP | SE.TER.ENRR | percent_education_total_gov_expenditure | SP.POP.1564.TO.ZS | SP.POP.TOTL | UIS.EA.3T6.AG25T99 | UIS.GER.4 | UIS.XGDP.23.FSGOV | UIS.XGDP.4.FSGOV | UIS.XGDP.56.FSGOV | total_enrolment | gov_expenditure |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | East Asia & Pacific | Australia | AUS | 46.756116 | 35281.395362 | 249.607498 | 67.03891 | 13.360160 | 66.788576 | 1.915300e+07 | NaN | 61.390049 | 1.88884 | 0.07649 | 1.14633 | 126.012152 | 3.11166 |
| 1 | East Asia & Pacific | Brunei Darussalam | BRN | 8.996285 | 82049.580860 | 67.462151 | 12.69113 | 8.920740 | 66.955147 | 3.332410e+05 | NaN | 1.296230 | NaN | NaN | NaN | 27.149837 | NaN |
| 2 | East Asia & Pacific | China | CHN | 1.775913 | 3700.743648 | 38.959030 | 7.72048 | 20.484921 | 68.462574 | 1.262645e+09 | NaN | 5.307240 | NaN | NaN | NaN | 17.328917 | NaN |
| 3 | East Asia & Pacific | Fiji | FJI | 1.496855 | 6673.847391 | 59.116379 | NaN | 20.484921 | 61.538812 | 8.112230e+05 | NaN | 2.885000 | NaN | NaN | 0.84457 | 31.000689 | NaN |
| 4 | East Asia & Pacific | Japan | JPN | 29.990740 | 33871.843545 | 100.454224 | 48.73653 | 9.930410 | 68.232188 | 1.268430e+08 | NaN | 0.844730 | 1.44606 | NaN | 0.54858 | 50.011828 | NaN |
L'ACP est une variante des méthode d'analyse factorielle utilisées lorsque les données sont quantitatives( nos indicateurs sont tous quantitatifs). Elle va nous aider à:
Transformation des données
# Standardisation de la base
scaled_data = pd.DataFrame(MinMaxScaler().fit_transform(data_pivot[list_features]),
columns=list_features,
index=pd.MultiIndex.from_frame(data_pivot[["region", "country_name", "country_code"]]))
scaled_data
| internet_users | gdp_per_capita | total_enrolment | percent_education_total_gov_expenditure | |||
|---|---|---|---|---|---|---|
| region | country_name | country_code | ||||
| East Asia & Pacific | Australia | AUS | 0.898952 | 0.303129 | 1.000000 | 0.325107 |
| Brunei Darussalam | BRN | 0.171331 | 0.749327 | 0.179070 | 0.153203 | |
| China | CHN | 0.032197 | 0.001830 | 0.097519 | 0.600994 | |
| Fiji | FJI | 0.026820 | 0.030196 | 0.211046 | 0.600994 | |
| Japan | JPN | 0.575888 | 0.289681 | 0.368910 | 0.192299 | |
| ... | ... | ... | ... | ... | ... | ... |
| Sub-Saharan Africa | Equatorial Guinea | GNQ | 0.000526 | 0.069492 | 0.000954 | 0.362172 |
| Mauritius | MUS | 0.138289 | 0.072206 | 0.281844 | 0.362172 | |
| Namibia | NAM | 0.029669 | 0.024779 | 0.088199 | 0.656760 | |
| Seychelles | SYC | 0.140487 | 0.142577 | 0.286187 | 0.362172 | |
| South Africa | ZAF | 0.101041 | 0.059216 | 0.321362 | 0.362172 |
92 rows × 4 columns
g = sns.PairGrid(data_pivot[list_features])
g.map_upper(sns.regplot)
g.map_lower(plt.scatter)
g.map_diag(plt.hist)
plt.show()
l'observation des nuages de points nous indique une tendance lineaire entre les variables. Donc presence de correlations entre les indicateurs.
Avant de réaliser l'ACP, on doit tester l’intérêt de l’ACP en vérifiant s’il est possible de compresser efficacement l’information disponible. Pour cela, nous allons effectuer le test de sphéricité de Bartlett. Le test de sphéricité de Bartlett vérifie l’hypothèse nulle selon laquelle toutes les corrélations entre Xj et Xk (avec j différent de k) seraient égales à zéro. C'est-à-dire, on cherche à tester l’hypothèse suivante: H0 : R = matrice identité ⇒ c-à-d les variables sont deux à deux indépendantes Où R est la matrice de corrélation.
Si H0 est vraie, les variables sont deux à deux orthogonales ⇒ ACP inutile
# le test de Bartlett.
from scipy.stats import bartlett
p = scipy.stats.bartlett( scaled_data.internet_users,scaled_data.gdp_per_capita,scaled_data.total_enrolment,scaled_data.percent_education_total_gov_expenditure)
p
BartlettResult(statistic=32.704415217275425, pvalue=3.7178129709993507e-07)
Ici, la pvalue est très inférieure aux seuils usuels( 1%, 5%, 10%). Donc on rejette l'hypothèse nulle.
# Application de l'ACP sur nos variables
# from fanalysis.pca import PCA
pca = PCA(n_components=None)
pca.fit(scaled_data)
explain_var_ratio = pca.explained_variance_ratio_
explain_var_ratio
array([0.59491999, 0.20313471, 0.11460959, 0.08733571])
Le premier axe contribue a lui seul 60% de l'inertie totale et le deuxieme axe 20%.
pca.components_
array([[ 0.83662436, 0.3611528 , 0.39598317, -0.11325045],
[ 0.31928986, -0.29687076, -0.15004695, 0.88735993],
[-0.1591248 , 0.86816556, -0.37426353, 0.28441988],
[-0.41568372, 0.16650817, 0.82499094, 0.34477822]])
# weighted: Variance expliquée de chaque axe multipliée par la coordonnée de chaque variable sur l'axe correspondant
weighted = (np.multiply(explain_var_ratio.reshape(1, -1).T, pca.components_)).sum(axis=0)
# normalized weight: la somme des poids doit etre égale à 1
normalize_weighted = (weighted / sum(weighted)).round(2)
features_weight_stat = dict(zip(list_features, normalize_weighted))
features_weight_stat
{'internet_users': 0.43,
'gdp_per_capita': 0.23,
'total_enrolment': 0.2,
'percent_education_total_gov_expenditure': 0.15}
Ainsi nous obtenons les poids pour chaque variable calcules a partir de la variance de chaque axe et les coordonnees sur l'axe. La variable internet_users vient en tete suivie du PIB par habitant.
# Calcul de l'attractivité pour selectionner les pays
scaled_data = (scaled_data
.assign(score=
lambda dframe: dframe.apply(scoring, features_weight=features_weight_stat, axis=1))
.reset_index()
)
scaled_data
| region | country_name | country_code | internet_users | gdp_per_capita | total_enrolment | percent_education_total_gov_expenditure | score | |
|---|---|---|---|---|---|---|---|---|
| 0 | East Asia & Pacific | Australia | AUS | 0.898952 | 0.303129 | 1.000000 | 0.325107 | 0.705035 |
| 1 | East Asia & Pacific | Brunei Darussalam | BRN | 0.171331 | 0.749327 | 0.179070 | 0.153203 | 0.304812 |
| 2 | East Asia & Pacific | China | CHN | 0.032197 | 0.001830 | 0.097519 | 0.600994 | 0.123919 |
| 3 | East Asia & Pacific | Fiji | FJI | 0.026820 | 0.030196 | 0.211046 | 0.600994 | 0.150836 |
| 4 | East Asia & Pacific | Japan | JPN | 0.575888 | 0.289681 | 0.368910 | 0.192299 | 0.416886 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 87 | Sub-Saharan Africa | Equatorial Guinea | GNQ | 0.000526 | 0.069492 | 0.000954 | 0.362172 | 0.070726 |
| 88 | Sub-Saharan Africa | Mauritius | MUS | 0.138289 | 0.072206 | 0.281844 | 0.362172 | 0.186766 |
| 89 | Sub-Saharan Africa | Namibia | NAM | 0.029669 | 0.024779 | 0.088199 | 0.656760 | 0.134611 |
| 90 | Sub-Saharan Africa | Seychelles | SYC | 0.140487 | 0.142577 | 0.286187 | 0.362172 | 0.204765 |
| 91 | Sub-Saharan Africa | South Africa | ZAF | 0.101041 | 0.059216 | 0.321362 | 0.362172 | 0.175665 |
92 rows × 8 columns
# Top 10 des pays potentiels
top_country = scaled_data.nlargest(N, columns=["score"], keep="all")
g = sns.catplot(data=top_country,
kind="bar", orient="h",
y="country_name", x="score", estimator=np.mean,
height=7, aspect=1.4, palette="Blues_r",
)
g.ax.set_title("Les pays selectionnés") ;
Ainsi en utilisant les ponderations issu de l'analyse factorielle l'on peut retenir les pays suivants: Norway, Switzerland, le Denmark, Ntherlands, Australia, l'ireland, le canada, Suisse, l'italie. Et le Norway apparait comme le premier pays en terme de qualité et d'attractivité dans le domaine éducatif.
(pd.melt(top_country,
id_vars=["country_name", "region"],
value_vars=list_features + ["score"],
var_name=None,
value_name='value',)
.pipe((sns.catplot, "data"), kind="swarm",
y="country_name", x="value", hue="variable", height=5, aspect=1.5
)
);
A travers ce graphique, il est clair que les pays ayant un score élevé ont été plus tirés par leur taux d'utilisation d'internet qui est assez élevé. En plus ces pays affichent des élevées pour toutes les variables.
# top of region
scaled_data.groupby("region").score.mean().nlargest(n=6)
region North America 0.620367 East Asia & Pacific 0.366177 Europe & Central Asia 0.332619 Middle East & North Africa 0.240436 Latin America & Caribbean 0.197159 Sub-Saharan Africa 0.130659 Name: score, dtype: float64
scaled_data
| region | country_name | country_code | internet_users | gdp_per_capita | total_enrolment | percent_education_total_gov_expenditure | score | |
|---|---|---|---|---|---|---|---|---|
| 0 | East Asia & Pacific | Australia | AUS | 0.898952 | 0.303129 | 1.000000 | 0.325107 | 0.705035 |
| 1 | East Asia & Pacific | Brunei Darussalam | BRN | 0.171331 | 0.749327 | 0.179070 | 0.153203 | 0.304812 |
| 2 | East Asia & Pacific | China | CHN | 0.032197 | 0.001830 | 0.097519 | 0.600994 | 0.123919 |
| 3 | East Asia & Pacific | Fiji | FJI | 0.026820 | 0.030196 | 0.211046 | 0.600994 | 0.150836 |
| 4 | East Asia & Pacific | Japan | JPN | 0.575888 | 0.289681 | 0.368910 | 0.192299 | 0.416886 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 87 | Sub-Saharan Africa | Equatorial Guinea | GNQ | 0.000526 | 0.069492 | 0.000954 | 0.362172 | 0.070726 |
| 88 | Sub-Saharan Africa | Mauritius | MUS | 0.138289 | 0.072206 | 0.281844 | 0.362172 | 0.186766 |
| 89 | Sub-Saharan Africa | Namibia | NAM | 0.029669 | 0.024779 | 0.088199 | 0.656760 | 0.134611 |
| 90 | Sub-Saharan Africa | Seychelles | SYC | 0.140487 | 0.142577 | 0.286187 | 0.362172 | 0.204765 |
| 91 | Sub-Saharan Africa | South Africa | ZAF | 0.101041 | 0.059216 | 0.321362 | 0.362172 | 0.175665 |
92 rows × 8 columns
Selon les régions, l'on doit opérer prioritairement dans les régions de l'Amerique du Nord, Asie de l'Est et Pacifique, l'Europe et l'Asie centrale,...
fig= px.choropleth(scaled_data.reset_index(),
locations="country_code",
color="score",
# hover_name="country_name",
hover_data=["region", "country_name"],
animation_frame=None,
color_continuous_scale='Plasma',
height=500,
width=None,
title="Pays score d'attractivité",
#range_color=(0, 12),
)
fig.show()
#!pip install -U kaleido
#Top 5 des pays par region
g = (scaled_data.groupby("region", as_index=False)
.apply(lambda g: g.nlargest(5, columns=["score"], keep="all"))
.pipe((sns.catplot, "data"),
kind="bar", orient="h", col="region", col_wrap=2,
y="country_name", x="score", estimator=np.mean,
height=3, aspect=1.5, palette="husl", sharey=False
)
)
C:\ProgramData\Anaconda3\lib\site-packages\seaborn\categorical.py:3795: UserWarning: Setting `sharey=False` with `color=None` may cause different levels of the `y` variable to share colors. This will change in a future version.
Nous avons les pays potentiels par région: Par exemple en Amérique du Nord: On retient Les USA et le Canada; en Afrique subsaharienne Nous avons Seychelles, le Mauritius, l'Afrique du Sud, Botswana et Namibie,...
Décision:
En termes d'investissement dans le domaine de l'éducation, les pays suivants peuvent etre retenus selon les deux méthodes.
Méthode de pondération: Norvège, Suisse, Danemark, Pays-Bas, Autriche, Irlande, Canada, Suède, Italie et Australie.
Méthode de l'ACP: Norvège, Autriche, Nouvelle-Zélande, Canada, Suède, Corée, Suisse, Finlande, États-Unis, Islande.
Nous retenons les pays fournis par la deuxième méthode qui est plus efficace car méthode statistique au lieu de la première qui est une affectation de coeficients selon l'importance que nous accordons à chaque variable.
Donc les pays les plus attractifs sont prioritairement: Norvège, Autriche, Nouvelle-Zélande, Canada, Suède, Corée, Suisse, Finlande, États-Unis, Island.
Apport:
Ce travail nous a permis d'aborder plusieurs méthodes du cours(Traitement, Visualisation, description,...). La finalisation de ce projet nous a montré de nombreux défis notamment sur le plan de traitement des données et aussi décisionnel. Il nous a permis de pouvoir guider une entreprise dans son projet d'expansion à l'international dans le domaine éducatif Aussi, nous avons pu obtenir les pays potentiels par ordre de priorité en terme d'invesrtissement.
Limites:
En matière d'investissement, la prevision sur de long terme de l'évolution du marché est necessaire. Il serait intéressant de connaitre la dynamique des indicateurs pour chacun de ces pays. Par exemple un pays émergent non considéré peut se retrouver favorable à l'investissement ( horizon 5 ou 10 ans).